/**
 * This class manages all interactions with the FirstResponder database on the device.
 * Currently, this database only contains one table - Locations - which contains both apparatuses
 * and destinations. 
 * Destinations have type "static", whereas apparatuses have type "dynamic".
 */

package com.firstresponder.db;

import java.util.ArrayList;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.util.Log;

public class FirstResponderDB {
	
	private SQLiteDatabase db;
	private final Context context;
	private final FirstResponderDBHelper dbHelper;
	
	/**
	 * create an instance of the database manager
	 * @param context
	 */
	public FirstResponderDB(Context c)
	{
		Log.d("FirstResponderDB", "in constructor");
		context = c;
		dbHelper = new FirstResponderDBHelper(context, DBConstants.DATABASE_NAME, null,
				                            DBConstants.DATABASE_VERSION);
	}

	/**
	 * open the database for writing
	 * @throws SQLiteException if the database can't be opened
	 */
	public void openForWrite() throws SQLiteException
	{
		Log.d("FirstResponderDB", "in openForWrite");
		db = dbHelper.getWritableDatabase();		
	}
	
	/**
	 * open the database for reading
	 * @throws SQLiteException if the database can't be opened
	 */
	public void openForRead() throws SQLiteException
	{
		Log.d("FirstResponderDB", "in openForRead");
	    db = dbHelper.getReadableDatabase();
		
	}
	

	
	/**
	 * insert one record into the Locations table
	 * @param loc a Location object
	 * @return the number of records inserted or -1 if the insert failed
	 * @throws SQLiteException 
	 */
	public long insertLocation(Location loc) throws SQLiteException
	{
		Log.d("FirstResponderDB", "in insertLocation");
		try{
			openForWrite();
			ContentValues locationInfo = new ContentValues();
			locationInfo.put(DBConstants.LocationConstants.DEPT_ID, loc.getDept_id());
			locationInfo.put(DBConstants.LocationConstants.LOCATION_KEY, loc.getLocation_key());
			locationInfo.put(DBConstants.LocationConstants.SHORT_NAME, loc.getShortName());
			locationInfo.put(DBConstants.LocationConstants.MAC_ADDR, loc.getMacAddress());
			locationInfo.put(DBConstants.LocationConstants.TYPE, loc.getType());
			locationInfo.put(DBConstants.LocationConstants.CURR_STATUS, loc.getCurrentStatus());
			locationInfo.put(DBConstants.LocationConstants.CURR_LAT, loc.getCurrLat());
			locationInfo.put(DBConstants.LocationConstants.CURR_LONG, loc.getCurrLong());
			locationInfo.put(DBConstants.LocationConstants.PRIORITY, loc.getPriority());
			return db.insert(DBConstants.LocationConstants.LOCATION_TABLE, null, locationInfo);
		}
	
		finally {
			if (db != null)
				db.close();
		}
	}
	
	/**
	 * returns all location records in the Location table
	 * @return an ArrayList of Location objects, which will be empty if no records were retrieved
	 * @throws SQLiteException
	 */
	public ArrayList<Location> getLocations() throws SQLiteException
	{
		Log.d("FirstResponderDB", "in getLocations");
		Cursor curs = null;
		try {
			ArrayList<Location> locs = new ArrayList<Location>();
		
			Location oneLoc = new Location();
			openForRead();
			curs = db.query(DBConstants.LocationConstants.LOCATION_TABLE, null, null, null, null, null, null);
			int numRecords = curs.getCount();
			Log.d("FirstResponderDB", "there are " + numRecords+ " records returned");
			if (numRecords > 0)
			{
				if (curs.moveToFirst())
				{
					do
					{
						Log.d("FirstResponderDB"," looking at location record");
						oneLoc.setLocation_key(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.LOCATION_KEY)));
						oneLoc.setDept_id(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.DEPT_ID)));
						oneLoc.setShortName(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.SHORT_NAME)));
						oneLoc.setMacAddress(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.MAC_ADDR)));
						oneLoc.setType(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.TYPE)));
						oneLoc.setCurrentStatus(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.CURR_STATUS)));
						oneLoc.setCurrLat(curs.getDouble(
								curs.getColumnIndex(DBConstants.LocationConstants.CURR_LAT)));
						oneLoc.setCurrLong(curs.getDouble(
								curs.getColumnIndex(DBConstants.LocationConstants.CURR_LONG)));
						oneLoc.setPriority(curs.getInt(
								curs.getColumnIndex(DBConstants.LocationConstants.PRIORITY)));
						Log.d("FirstResponderDB", "short name is " + oneLoc.getShortName());
						locs.add(oneLoc);
					}while (curs.moveToNext());
				}
			} // end processing non-empty cursor
			
			
			return locs;
		} 
		finally {
			if (curs!=null)
				curs.close();
			if (db != null)
				db.close();
		}
	}
	
	/**
	 * get a location based on its priority.
	 * This is useful when getting the default destination, which could be the highest
	 * priority location
	 * we are assuming that priorities will be unique
	 * @param priority
	 * @return a Location object or null if not found
	 */
	public Location getLocationByPriority(String priority)
	{
		Log.d("FirstResponderDB", "in getLocationsByPriority");
		Location returnLocation = null;
		Cursor curs = null;
		try {
			
			openForRead();
			curs = db.query(DBConstants.LocationConstants.LOCATION_TABLE, null, DBConstants.LocationConstants.PRIORITY + "=?", new String[]{priority}, null, null, null);
			int numRecords = curs.getCount();
			Log.d("FirstResponderDB", "there are " + numRecords+ " records returned");
			
				if (curs.moveToFirst())
				{
					    returnLocation = new Location();
						Log.d("FirstResponderDB"," looking at location record");
						returnLocation.setLocation_key(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.LOCATION_KEY)));
						returnLocation.setDept_id(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.DEPT_ID)));
						returnLocation.setShortName(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.SHORT_NAME)));
						returnLocation.setMacAddress(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.MAC_ADDR)));
						returnLocation.setType(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.TYPE)));
						returnLocation.setCurrentStatus(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.CURR_STATUS)));
						returnLocation.setCurrLat(curs.getDouble(
								curs.getColumnIndex(DBConstants.LocationConstants.CURR_LAT)));
						returnLocation.setCurrLong(curs.getDouble(
								curs.getColumnIndex(DBConstants.LocationConstants.CURR_LONG)));
						returnLocation.setPriority(curs.getInt(
								curs.getColumnIndex(DBConstants.LocationConstants.PRIORITY)));
						Log.d("FirstResponderDB", "short name is " + returnLocation.getShortName());
						
					}
				else // cursor was empty
					Log.d("FirstResponderDB", "no record found with priority " + priority);
			return returnLocation;
		} finally {
			Log.d("FirstResponderDB", "closing the cursor and database");
			if (curs != null)
				curs.close();
			if (db != null)
				db.close();
		}
		
	}
	
/**
 * return a location based on the location key, which is generated on the web server side
 * and maintained on the phone database as well.
 * @param loc_id
 * @return a Location object or null if not found
 */
	public Location getLocationById(String loc_id)
	{
		Log.d("FirstResponderDB", "in getLocationsById");
		Location returnLocation = null;
		Cursor curs = null;
		try {
			
			openForRead();
			curs = db.query(DBConstants.LocationConstants.LOCATION_TABLE, null, DBConstants.LocationConstants.LOCATION_KEY + "=?", new String[]{loc_id}, null, null, null);
			int numRecords = curs.getCount();
			Log.d("FirstResponderDB", "there are " + numRecords+ " records returned");
			
				if (curs.moveToFirst())
				{
					    returnLocation = new Location();
						Log.d("FirstResponderDB"," looking at location record");
						returnLocation.setLocation_key(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.LOCATION_KEY)));
						returnLocation.setDept_id(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.DEPT_ID)));
						returnLocation.setShortName(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.SHORT_NAME)));
						returnLocation.setMacAddress(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.MAC_ADDR)));
						returnLocation.setType(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.TYPE)));
						returnLocation.setCurrentStatus(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.CURR_STATUS)));
						returnLocation.setCurrLat(curs.getDouble(
								curs.getColumnIndex(DBConstants.LocationConstants.CURR_LAT)));
						returnLocation.setCurrLong(curs.getDouble(
								curs.getColumnIndex(DBConstants.LocationConstants.CURR_LONG)));
						returnLocation.setPriority(curs.getInt(
								curs.getColumnIndex(DBConstants.LocationConstants.PRIORITY)));
						Log.d("FirstResponderDB", "short name is " + returnLocation.getShortName());
						
					}
				else // cursor was empty
					Log.d("FirstResponderDB", "no record found with id " + loc_id);
			return returnLocation;
		} finally {
			Log.d("FirstResponderDB", "closing the cursor and database");
			if (curs != null)
				curs.close();
			if (db != null)
				db.close();
		}
		
	}
	
	/**
	 * get a location or locations based on the  short name field
	 * @param name - the short name of a location
	 * @return a Location object or null if there is no record with that name
	 */
	public ArrayList<Location> getLocationsByName(String name)
	{
		Log.d("FirstResponderDB", "in getLocationsByName");
		Cursor curs = null;
		try {
			ArrayList<Location> locs = new ArrayList<Location>();
		
			Location oneLoc = new Location();
			openForRead();
			
			// the only selection criteria is the short name field, and we will return all columns
			curs = db.query(DBConstants.LocationConstants.LOCATION_TABLE, null, DBConstants.LocationConstants.SHORT_NAME + "=?", new String[]{name}, null, null, null);
			int numRecords = curs.getCount();
			Log.d("FirstResponderDB", "there are " + numRecords+ " records returned");
			if (numRecords > 0)
			{
				if (curs.moveToFirst())
				{
					do
					{
						Log.d("FirstResponderDB"," looking at location record");
						oneLoc.setLocation_key(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.LOCATION_KEY)));
						oneLoc.setDept_id(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.DEPT_ID)));
						oneLoc.setShortName(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.SHORT_NAME)));
						oneLoc.setMacAddress(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.MAC_ADDR)));
						oneLoc.setType(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.TYPE)));
						oneLoc.setCurrentStatus(curs.getString(
								curs.getColumnIndex(DBConstants.LocationConstants.CURR_STATUS)));
						oneLoc.setCurrLat(curs.getDouble(
								curs.getColumnIndex(DBConstants.LocationConstants.CURR_LAT)));
						oneLoc.setCurrLong(curs.getDouble(
								curs.getColumnIndex(DBConstants.LocationConstants.CURR_LONG)));
						oneLoc.setPriority(curs.getInt(
								curs.getColumnIndex(DBConstants.LocationConstants.PRIORITY)));
						Log.d("FirstResponderDB", "short name is " + oneLoc.getShortName());
						locs.add(oneLoc);
					}while (curs.moveToNext());
				}
			} // end processing non-empty cursor
			
			
			return locs;
		} 
		finally {
			if (curs!= null)
				curs.close();
			if (db != null)
				db.close();
		}
	}

	/**
	 * Update an existing record.
	 * This method assumes that a record with a key that matches the location_key field in
	 * Location exists in the database.
	 * If no such record exists, it will not do the update, and will return a 0
	 * Otherwise, the record will be updated with all of the values in the Location object
	 * @param updatedLoc, a Location object containing the updated values
	 * @return the number of updated records,which should be 1, or 0 if no record is updated
	 */
	public long updateLocation(Location updatedLoc)
	{
		Log.d("FirstResponderDB", "in updateLocation");
		try{
			openForWrite();
			ContentValues locationInfo = new ContentValues();
			locationInfo.put(DBConstants.LocationConstants.DEPT_ID, updatedLoc.getDept_id());
			locationInfo.put(DBConstants.LocationConstants.LOCATION_KEY, updatedLoc.getLocation_key());
			locationInfo.put(DBConstants.LocationConstants.SHORT_NAME, updatedLoc.getShortName());
			locationInfo.put(DBConstants.LocationConstants.MAC_ADDR, updatedLoc.getMacAddress());
			locationInfo.put(DBConstants.LocationConstants.TYPE, updatedLoc.getType());
			locationInfo.put(DBConstants.LocationConstants.CURR_STATUS, updatedLoc.getCurrentStatus());
			locationInfo.put(DBConstants.LocationConstants.CURR_LAT, updatedLoc.getCurrLat());
			locationInfo.put(DBConstants.LocationConstants.CURR_LONG, updatedLoc.getCurrLong());
			locationInfo.put(DBConstants.LocationConstants.PRIORITY, updatedLoc.getPriority());
			return db.update(DBConstants.LocationConstants.LOCATION_TABLE, locationInfo,
					                  DBConstants.LocationConstants.LOCATION_KEY+"=?",
					                  new String [] {updatedLoc.getLocation_key()});
		}
	
		finally {
			if (db != null)
				db.close();
		}
		     
	}
}
